# -*- encoding: utf-8 -*-

# Copyright 2010 István Szentandrási
# <etude-music-player@googlegroups.com>

# This file is part of Etude.
#
# Etude is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as 
# published by the Free Software Foundation, either version 3 
# of the License, or (at your option) any later version.
#
# Etude is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Etude. If not, see <http://www.gnu.org/licenses/>.

from . import _

import etude.plugins as ep
import gtk
import gobject
HAVE_GL = True
try:
    from gtk.gtkgl.apputils import *
    import OpenGL
    import numpy as np
except ImportError:
    HAVE_GL = False

import visualization_wrapper as visw
import libvisual
DATA_SIZE = 1024
VIZ_TIMEOUT = 1000.0/100.0
VIS_ERROR = "LibVisual Error: "
import time
import ctypes

class VisualizationLibVisual(ep.PluginPanel):

    _type = ep.E_PANEL_TYPE_OTHER
    _short_name = "Visualiation (Libvisual)"
    _show_name = _("Visualiation (Libvisual)")
    _short_descr = _("Visualization using libvisual library.")
    _version = "0.1"
    _unique = "VisualizationLibvisual-0.1" # short name + version is enough, just to identify loaded
    _title = _("Visualization")
    _config = {'fps': '24'}
    __author__= "Szentandrási István"

    """
    Visualization using libvisual library
    """

    def __init__(self, control):
        ep.PluginPanel.__init__(self, control)
        if not HAVE_GL:
            print("Sry libraries missing")
            self.unload()
            return
        self.data = np.array([], 'f')
        self.xmms_vis = visw.VisWrapper(self)
        print("initializing visualization")
        self.xmms_vis.init_visualization({'type': 'pcm', 'stereo': "1"})


        self.visscene = VisScene()
        self.glarea = GLArea(self.visscene)
        self.add(self.glarea)

        rendertime = 1000.0/float(self.get_config('fps'))
        self.chunk_timer = gobject.timeout_add(int(VIZ_TIMEOUT), self.get_data)
        self.timer = gobject.timeout_add(int(rendertime), self.refresh)
        self.enabled = True
        self.glarea.connect('window-state-event', self.windowstate)

        self.show_all()

    def windowstate(self, widget, event):
        if event.changed_mask & gtk.gdk.WINDOW_STATE_FULLSCREEN:
            if event.new_event_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
                self.fullscreen = True
            else:
                self.fullscreen = False

    def get_data(self):
        data = self.xmms_vis.chunk_get(0, 0, DATA_SIZE)
        if len(data) == DATA_SIZE:
            self.data = np.array(data, 'f')
            self.visscene.libv.set_data_list(self.data)
        return self.enabled

    def refresh(self):
        #rendertime = 1000.0/float(self.get_config('fps'))
        self.visscene.data = self.data
        if(len(self.visscene.data) == DATA_SIZE):
            try:
                self.glarea.window.invalidate_rect(self.glarea.allocation, False)
            except:
                return False
        return self.enabled

    def unload(self):
        ep.PluginPanel.unload(self)
        self.enabled = False

class VisScene(GLScene, GLSceneButton, GLSceneKey):

    def __init__(self, texwidth=512, texheight=512):
        GLScene.__init__(self,
                gtk.gdkgl.MODE_RGBA |
                gtk.gdkgl.MODE_DOUBLE|
                gtk.gdkgl.MODE_DEPTH)
        GLSceneButton.__init__(self)
        GLSceneKey.__init__(self)

        self.texwidth = texwidth
        self.texheight = texheight

        self.width = texwidth
        self.height = texheight
        self.fullscreen = False

        self.libv = libvisual.LibVisual()
        if not self.libv.init(self.texwidth, self.texheight, "corona"):
            print self.libv.get_err_msg()
        else:
            print self.libv.get_err_msg()
            print "libvisual inited ok"
        self.data = np.array([])

    def set_actor(self, actor):
        if actor in self.libv.get_available_plugins():
            self.libv.set_actor(self.texwidth, self.texheight, actor)
            self.libv.sync(1)
            self.libv.depth_changed()
            self.reshape(self.width, self.height)
        else:
            print("actor %s not found in %s" % (actor, self.libv.get_available_plugins()))

    def key_press(self, width, height, event):
        if event.keyval in 'fF':
            #for some reason segfaulted
            if self.fullscreen:
                print('setting unfullscreen')
                #self.glarea.get_window().unfulscreen()
            else:
                print('setting fullscreen')
                #self.glarea.get_window().fullscreen()
            self.fullscreen = not self.fullscreen

    def key_release(self, width, height, event):
        pass

    def button_press(self, width, height, event):
        def set_actor(widget, data):
            self.set_actor(data)
        if event.button == 3:
            menu = gtk.Menu()
            for lab in ("oinksie", "corona", "jess", "bumpscope", "jakdaw", "lv_gltest"):
                item = gtk.MenuItem(label= lab)
                item.connect('activate', set_actor, lab)
                menu.append(item)

            menu.show_all()
            menu.popup(None, None, None, 3, event.time, event.window)
        elif event.button == 2:
            if self.fullscreen:
                event.window.unfullscreen()
            else:
                event.window.fullscreen()
            self.fullscreen = not self.fullscreen

    def button_release(self, width, height, event):
        pass


    def init(self):
        glViewport(0, 0, self.width, self.height)
        glClearColor(0.0, 0.0, 0.0, 0.0)    # This Will Clear The Background Color To Black
        glDepthFunc(GL_LESS)                # The Type Of Depth Test To Do
        glEnable(GL_DEPTH_TEST)             # Enables Depth Testing
        glShadeModel(GL_SMOOTH)             # Enables Smooth Color Shading
        glClearDepth(1.0)                   # Enables Clearing Of The Depth Buffer
        if not self.libv.is_GL():
            self.setup_2d()
        self.init_texture()

    def init_texture(self):
        self.texi = glGenTextures(1)
        glBindTexture(GL_TEXTURE_2D, self.texi)   # 2d texture (x and y size)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)

    def setup_2d(self):
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        glOrtho(0, 1.0, 0, 1.0, 0.1, 100)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        glEnable(GL_TEXTURE_2D)

    def reshape(self, width, height):
        self.width = width
        self.height = height
        glViewport(0, 0, width, height);
        #print(self.libv.video_get_data())
        if self.libv.is_GL():
            print('resizing for opengl')
            if(not self.libv.video_set_dimension(width, height)):
                print(VIS_ERROR + "Unable to resize video.")

        if(not self.libv.actor_video_negotiate(0, 0, 0)):
            print (VIS_ERROR + "actor/video negotiation failed.")

        if(not self.libv.is_GL()):
            self.setup_2d()

    def resize_texture(self, width, height):
        self.texwidth = width
        self.texheight = height
        ## Here we give video a new size. */
        if(not self.libv.video_set_dimension(width, height)):
            print(VIS_ERROR + "Unable to resize video.")

        if(not self.libv.actor_video_negotiate(0, 0, 0)):
            print (VIS_ERROR + "actor/video negotiation failed.")

        if(not self.libv.is_GL()):
            self.setup_2d()


    def display(self, width, height):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glLoadIdentity()

        glDisable(GL_TEXTURE_2D)
        glDisable(GL_BLEND)
        
        self.libv.bin_run()
        if(not self.libv.is_GL()):
            # We have to render video's buffer.
            format = GL_R3_G3_B2 # Reasonable safety against reads outside of the buffer.
            bpp = self.libv.video_bpp_from_depth()

            if bpp == 4:
                format = GL_RGBA
            elif bpp == 3:
                format = GL_RGB;
            elif bpp == 2:
                format = GL_RGBA4;
            else:
                print(VIS_ERROR + "Wrong bpp")
                return

            #Draws the buffer to screen. */
            data = self.libv.video_get_pixels()
            glLoadIdentity()
            glEnable(GL_TEXTURE_2D)
            glBindTexture(GL_TEXTURE_2D, self.texi)
            #glPixelStorei(GL_UNPACK_ALIGNMENT,1)
            glTexImage2D(GL_TEXTURE_2D, 0, 3, self.texwidth, self.texheight, 0, format, GL_UNSIGNED_BYTE, data)
            del data
            glTranslatef(0.0, 0.0, -0.2)

            glBegin(GL_QUADS)
            glTexCoord2i(0,0)
            glVertex3f(0.0, 1.0, 0.0)
            glTexCoord2i(0,1)
            glVertex3f(0.0, 0.0, 0.0)
            glTexCoord2i(1,1)
            glVertex3f(1.0, 0.0, 0.0)
            glTexCoord2i(1,0)
            glVertex3f(1.0, 1.0, 0.0)
            glEnd()
            """
            # Draw a triangle
            glBegin(GL_POLYGON)                 # Start drawing a polygon
            glColor3f(1.0, 0.0, 0.0)            # Red
            glVertex3f(0.0, 1.0, 0.0)
            glColor3f(0.0, 1.0, 0.0)            # Green
            glVertex3f(0.0, 0.0, 0.0)
            glColor3f(0.0, 0.0, 1.0)            # Blue
            glVertex3f(1.0, 0.0, 0.0)
            glVertex3f(1.0, 1.0, 0.0)
            glEnd()                             # We are done with the polygon
            """
        #else if opengl already ok

